<template>
    <div class="layout-container">
        <div class="layout-container-left">
            <div ref="mapRef" class="map" />
        </div>

        <div class="layout-container-right">
            <div class="form-box">
                <el-form label-width="auto">
                    <el-form-item label="属性字段名">
                        <el-select v-model="paramsData.valueField">
                            <el-option v-for="item in valueFields" :value="item" />
                        </el-select>
                    </el-form-item>

                    <el-form-item label="矩阵类型">
                        <el-select v-model="paramsData.weightType">
                            <el-option value="KNN" />
                            <el-option value="DISTANCE_THRESHOLD" />
                            <el-option value="QUEEN" />
                            <el-option value="ROOK" />
                        </el-select>
                    </el-form-item>

                    <el-form-item label="邻居数量" v-if="paramsData.weightType==='KNN'">
                        <el-input v-model="paramsData.knnK" type="number" />
                    </el-form-item>

                    <el-form-item label="距离阈值" v-if="paramsData.weightType==='DISTANCE_THRESHOLD'">
                        <el-input v-model="paramsData.distanceThreshold" type="number"  />
                    </el-form-item>

                    <el-form-item label="检验次数">
                        <el-input v-model="paramsData.permutations" type="number" />
                    </el-form-item>

                    <el-form-item label="详细统计量">
                        <el-switch v-model="paramsData.includeStats" />
                    </el-form-item>

                    <el-form-item>
                        <GeoJsonUpload @uploadSuccess="loadMap" />
                    </el-form-item>

                    <el-form-item>
                        <el-button type="primary" @click="handleCalculate">计算</el-button>
                    </el-form-item>
                </el-form>
            </div>

            <el-divider />

            <div class="info-box">
                <h5>算法说明</h5>
                <p>计算全局空间自相关指数（取值范围 [-1,1]），>0 表示空间聚集（相似值集中），<0 表示空间离散（异值集中），0 表示随机分布。</p>

                <h5>使用范围</h5>
                <ol>
                    <li>判断整体空间分布模式（如城市 GDP 是否呈现聚集分布）；</li>
                    <li>验证空间是否存在相关性（如疾病发病率是否有地理聚集性）；</li>
                    <li>需结合显著性检验（P 值）判断结果可靠性。</li>
                </ol>
            </div>
        </div>

        <Result v-model="resultShow" :originalData="paramsData" :result="resultData" />
    </div>
</template>

<script setup>
import { onMounted, onUnmounted, ref } from "vue"
import { globalMoran }                 from "@/api/spatial"
import Result                          from "./components/Result.vue"
import GeoJsonUpload                   from "@/components/GeoJsonUpload.vue"
import Map                             from "ol/Map"
import View                            from "ol/View"
import GeoJSON                         from "ol/format/GeoJSON"
import VectorLayer                     from "ol/layer/Vector"
import VectorSource                    from "ol/source/Vector"
import { Circle, Fill, Stroke, Style } from "ol/style"
import { fromLonLat }                  from "ol/proj"
import TileLayer                       from "ol/layer/Tile"
import XYZ                             from "ol/source/XYZ"

let paramsData = ref({
    geoJson          : null,
    valueField       : "value",
    weightType       : "KNN",
    knnK             : 4,
    distanceThreshold: 1000,
    permutations     : 999,
    includeStats     : true,
})

let resultShow = ref(false)
let resultData = ref({})

function handleCalculate(){
    paramsData.value.geoJson = JSON.stringify(geojsonData)
    globalMoran(paramsData.value).then((res) => {
        resultData.value = res.data
        resultShow.value = true
    })
}

// 地图相关
let mapRef      = ref(null)
let map         = null
let geojsonData = null
let baseLayer   = null
let geoLayer    = null

// 销毁现有地图
function destroyMap(){
    if(map){
        // 移除所有图层
        if(baseLayer){
            map.removeLayer(baseLayer)
            baseLayer = null
        }
        if(geoLayer){
            map.removeLayer(geoLayer)
            geoLayer = null
        }
        // 清除地图实例
        map.setTarget(null)
        map = null
    }
}

let valueFields = ref([])

// 加载地图数据
function loadMap(data){
    destroyMap()
    // 缓存
    geojsonData                 = data
    valueFields.value           = Object.keys(data?.features?.[0]?.properties || {})
    paramsData.value.valueField = valueFields.value?.[0] || ""

    // 基础图层
    baseLayer = new TileLayer({
        source: new XYZ({
            url: "https://webrd0{1-4}.is.autonavi.com/appmaptile?style=7&x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1",
        }),
    })

    // 矢量图层
    geoLayer = new VectorLayer({
        source: new VectorSource({
            features: new GeoJSON().readFeatures(geojsonData, {
                dataProjection   : "EPSG:4326",
                featureProjection: "EPSG:3857",
            }),
        }),
        style : new Style({
            fill  : new Fill({ color: "rgba(75, 192, 192, 0.1)" }),
            stroke: new Stroke({ color: "#c04b8d", width: 2, lineDash: [ 5, 3 ] }),
            image : new Circle({
                radius: 5,
                fill  : new Fill({ color: "#84c1ec" }),
                stroke: new Stroke({ color: "#ffffff", width: 1.5 }),
            }),
        }),
    })

    // 创建map
    map = new Map({
        target  : mapRef.value,
        layers  : [ baseLayer, geoLayer ],
        view    : new View({
            center : fromLonLat([ 114.17, 22.28 ]),
            zoom   : 8,
            maxZoom: 18,
        }),
        controls: [],
    })

    const source = geoLayer.getSource()
    const extent = source.getExtent()
    map.getView().fit(extent, {
        padding : [ 50, 50, 50, 50 ],
        duration: 1000,
    })
}

onMounted(() => {
    fetch("/hongKong.json")
    .then(response => response.json())
    .then(loadMap)
    .catch(error => console.error("加载GeoJSON失败:", error))
})

onUnmounted(() => {
    if(map){
        map.setTarget(null)
        map = null
    }
})
</script>

<style scoped>
.map {
    height: 100%;
    width: 100%;
    position: relative;
}
</style>
